#define FBEXT_NO_LIBJPG
#define fbext_NoBuiltinInstanciations() 1
#include Once "fbgfx.bi"
#include once "fmod.bi"
#include Once "ext/xml/dom.bi"
'#include once "ext/graphics/png.bi"
#include once "ext/graphics/image.bi"
#include once "ext/graphics/manip.bi"
#include once "ext/math/vector2.bi"
#include once "ext/math/vector3.bi"
#include once "ext/file/console.bi"
#include once "ext/math/random.bi"
#include once "ext/strings/strsplit.bi"
#include once "ext/graphics/font.bi"
#include once "notifications.bas"

#ifdef __FB_WIN32__
#define SLASH "\"
#define CONFIG_DIR environ("APPDATA") & SLASH & "drmudball_dx" & SLASH
#endif

#ifdef __FB_LINUX__
#define SLASH "/"
#define CONFIG_DIR environ("HOME") & SLASH & ".config" & SLASH & "drmudball_dx" & SLASH
#endif

using ext.math

''Constants
const as integer SCR_AREA = 640*480
const as single particle_speed = 50

''UDTs
type lstruct
    a as single
    p as vec2f
end type

type particle_struct
    as vec2f p, v
end type

type sballs
    p as vec2f
    c as uinteger
end type

type big_hairy_ballxorz_struct
    as integer active, dead, glow, sound_channel, scount, bad
    as uinteger col
    as single r,m,s
    as vec2f p, v, op
    streamer(20) as sballs
    sound_time as double
end type

type player_struct
    as integer selected, popped
    as uinteger max_balls, level, timer_level, lives
    as ulongint score
    as single level_fill
    as big_hairy_ballxorz_struct ptr ball
end type

''Enumerations
enum

SFX_BOUNCE = 1
SFX_BOUNCE2
SFX_POP
SFX_GROW

end enum

enum powerups
PU_GRAVITY = -1
PU_LOSPD = -2
PU_HISPD = -3
PU_HISPD_GROW = -4
PU_LOSPD_GROW = -5
PU_SHIELD = -6
PU_SIDES = -7
PU_MOTIME = -8
PU_NOTIME = -9
PU_GRAVITRON = -10
PU_ENERGY = -11
end enum


''Procedure declarations
declare sub check_ball_2screen( byref ball as big_hairy_ballxorz_struct, byval loop_time as single )
declare sub level_up( byref player as player_struct, balls() as big_hairy_ballxorz_struct, byref add_level as integer )
declare function in_aabb( byref v1 as vec2f, byref v2 as vec2f, byref box as integer ) as integer
declare sub game_over(byref player as player_struct)
declare sub Load_Sfx( byref filename as string, _SFX() as FSound_Sample ptr )
declare sub LoadSettings( byref wf as integer, byref mvol as integer, byref svol as integer, byref sfps as integer )
declare function scaletoubyte(byval v as integer) as integer
declare function mixalpha( byval colour as uinteger, byval mixer as integer ) as uinteger
declare sub intro()
declare sub showHelp()
declare function playNextSong() as integer
declare sub addPUBustron( byval t as powerups )

''Powerup ending procedures
declare sub end_lospeed_bustrons(byval x as any ptr)
declare sub end_hispeed_bustrons(byval x as any ptr)
declare sub end_higrowth(byval x as any ptr)
declare sub end_logrowth(byval x as any ptr)
declare sub end_shield(byval x as any ptr )
declare sub end_sides(byval x as any ptr )
declare sub end_gravitron( byval x as any ptr )

''Shared Variables
dim shared song as FSOUND_Stream ptr
dim shared con as ext.Console
dim shared bg_image as fb.image ptr
dim shared as single growth_rate, bspeed
dim shared Messages as notification_list
dim shared as fb.image ptr mFont
dim shared as single curBallspeed
dim shared as single fgrav, gravitron_size
dim shared as double cooldown
dim shared as integer shield_active, sides_active, gravitron_active
dim shared as double remove_pu_b
dim shared as integer sm

''******Main*******

randomize timer

screenres 640,480,32,,FB.GFX_ALPHA_PRIMITIVES
''Our initial window title
windowtitle "Dr. Mudball's Laboratory!"
locate 24,30
print "Loading..."
chdir exepath
var fbi = ext.gfx.png.load("../img/warning.png")
put(0,0), fbi, pset

dim sfx() as FSound_Sample ptr
dim as player_struct player
dim shared as big_hairy_ballxorz_struct ball()
dim as particle_struct particle(275)
dim as lstruct rpoint(1 to 20, 1 to 10)
dim as integer old_growth
dim shared as ext.gfx.image ptr wfbg_image

dim as integer grow_channel, pop_channel, fps, music_volume, sfx_volume, omx, omy, mx, my
dim as integer mbutt, ball_is_active, filled_area, Big_Hairy_Ball_Count, pop_count
dim shared as integer song_channel, haveSound
dim as integer pre_paused_mx, pre_paused_my
dim as ulongint temp_score
dim as integer song_pos
dim as double notifcation_paused


dim as uinteger ptr scr = screenptr
dim as ext.gfx.image ptr scorecard
dim as ext.gfx.image ptr banner
dim as ext.gfx.image ptr oot_img
dim as ext.gfx.image ptr ooqfp_img
dim as ext.gfx.image ptr note_img
dim as ext.gfx.image ptr ipu_gravity
dim as ext.gfx.image ptr ipu_lospd
dim as ext.gfx.image ptr ipu_hispd
dim as ext.gfx.image ptr ipu_hispd_grow
dim as ext.gfx.image ptr ipu_lospd_grow
dim as ext.gfx.image ptr ipu_shield
dim as ext.gfx.image ptr ipu_sides
dim as ext.gfx.image ptr ipu_timeup
dim as ext.gfx.image ptr ipu_timedown
dim as ext.gfx.image ptr ipu_gravitron
dim as ext.gfx.image ptr ipu_energy

dim as single dist, grow
dim as double a, this_timer, last_key_time, loop_time, fps_timer, remove_pu_bold

dim as string fps_String
dim as vec3f cam_targ

''These variables affect how we draw things.
Var isPaused = 0
Var drawFilled = 1
var showFPS = 0
var remove_pu = 0

sm = 0
if command() = "mudlovesmis" then sm = 1
FSOUND_SetMinHardwareChannels( 16 )
#ifdef __FB_LINUX__
FSOUND_SetOutput ( FSOUND_OUTPUT_ALSA )
#endif
haveSound = FSOUND_Init(44100, 32, 0)

if haveSound <> 1 then

    con.WriteLine("FMOD Error: " & FSOUND_GetErrorString(haveSound))

else

    con.WriteLine("FMOD Initialized.")

end if

''Load our sound effects
chdir exepath()
Load_Sfx( "snd/fx/bounce.wav", sfx() )
Load_Sfx( "snd/fx/bounce2.wav", sfx() )
Load_Sfx( "snd/fx/pop3.wav", sfx() )
Load_Sfx( "snd/fx/grow.wav", sfx() )


dim shared curMessage as notification ptr
curMessage = 0

sleep 5000
delete fbi
fbi = ext.gfx.png.load("../img/wwzjd.png")
var zjwins = FSOUND_Sample_Load(FSOUND_FREE, "snd/fx/donteatmaibrainzj.ogg", FSOUND_HW2D or FSOUND_LOOP_OFF, 0, 0)
if zjwins = 0 then con.WriteLine("Error loading: snd/fx/donteatmaibrainzj.ogg")
var zjwinplay = FSOUND_PlaySoundEx( FSOUND_FREE, zjwins, 0, 0 )
if zjwinplay = 0 then con.WriteLine("ZOMBIE JESUS ATE MY BRAINS!!!")
FSOUND_Update()
FSOUND_SetSFXMasterVolume( 100 )

put(0,0),fbi, pset
sleep 3500

setmouse(320,240)
curBallspeed = 150f
fgrav = 9.8
sleep 1000


zjwins = FSOUND_Sample_Load(FSOUND_FREE, "snd/fx/lolscream.ogg", FSOUND_HW2D or FSOUND_LOOP_OFF, 0, 0)
if zjwins = 0 then con.WriteLine("Error loading: snd/fx/lolscream.ogg")
zjwinplay = FSOUND_PlaySoundEx( FSOUND_FREE, zjwins, 0, 0 )
if zjwinplay = 0 then con.WriteLine("ZOMBIE JESUS ATE MY BRAINS!!!")
FSOUND_Update()

sleep 2000
FSOUND_Sample_free(zjwins)

delete fbi
bg_image = imagecreate(640,480)
wfbg_image = ext.gfx.loadimage("../img/wfbg.png")
ithasbegun:
chdir exepath()
scorecard = ext.gfx.loadimage("../img/scorecard.png")
oot_img = ext.gfx.loadimage("../img/oot.png")
ooqfp_img = ext.gfx.loadimage("../img/ooqfp.png")
note_img = ext.gfx.loadimage("../img/notes.png")

banner = ext.gfx.loadimage("../img/banner.png")

ipu_gravity = ext.gfx.loadimage("../img/notes_pu_gravity_s.png")
ipu_lospd = ext.gfx.loadimage("../img/notes_pu_lospd_s.png")
ipu_hispd = ext.gfx.loadimage("../img/notes_pu_hispd_s.png")
ipu_hispd_grow = ext.gfx.loadimage("../img/notes_pu_higrow_s.png")
ipu_lospd_grow = ext.gfx.loadimage("../img/notes_pu_logrow_s.png")
ipu_shield = ext.gfx.loadimage("../img/notes_pu_shield_s.png")
ipu_sides = ext.gfx.loadimage("../img/notes_pu_sides_s.png")
ipu_timeup = ext.gfx.loadimage("../img/notes_pu_motime_s.png")
ipu_timedown = ext.gfx.loadimage("../img/notes_pu_notime_s.png")
ipu_gravitron = ext.gfx.loadimage("../img/notes_pu_blackhole_s.png")
ipu_energy = ext.gfx.loadimage("../img/notes_pu_energy_s.png")

''Initialize settings from settings file.
LoadSettings(drawFilled, music_volume, sfx_volume, showFPS)
ext.gfx.font.loadttf("../img/ca.ttf",mFont,,,20)
player.score = 0
player.level = 0
player.max_balls = 0

''Load our initial background song.
song_channel = playNextSong()

if song = 0 then
    dim as uinteger sounderr = FSound_GetError()
    con.WriteLine( "FMOD error: " & FSOUND_GetErrorString(sounderr) )
    'DOW!
    con.WriteLine( "Running without sound." )
    'Sleep 5000
end if

''Setup our 3d listener stuff and volumes from the settings file.
FSOUND_3D_SetDistanceFactor( 1280.0 )
FSOUND_3D_SetRolloffFactor( 0.001 )



''Start playing the music
song_channel = FSOUND_Stream_Play( FSOUND_FREE, song )
FSOUND_SetReserved( song_channel, 1 )
FSOUND_SetVolume ( song_channel, music_volume )
FSOUND_3D_SetAttributes( song_channel, @cam_targ.x, 0 )

grow_channel = FSOUND_PlaySoundEx( FSOUND_FREE, SFX(SFX_GROW), 0, 1 )
FSOUND_SetLoopMode( grow_channel, FSOUND_LOOP_NORMAL )
FSOUND_SetPaused(grow_channel, 0)
FSOUND_SetReserved( grow_channel, 1 )
FSOUND_SetPaused( grow_channel, 1)


pop_channel = FSOUND_PlaySoundEx( FSOUND_FREE, SFX(SFX_POP), 0, 1 )
'FSOUND_SetLoopMode( pop_channel, FSOUND_LOOP_NORMAL )
'FSOUND_SetPaused(grow_channel, 0)
FSOUND_SetReserved( pop_channel, 1 )
'FSOUND_SetPaused( grow_channel, 1)



FSOUND_SetSFXMasterVolume( sfx_volume )
FSOUND_SetVolumeAbsolute( song_channel, music_volume )
FSOUND_Update()



''Call our nifty intro sequence
intro()

if sm = 1 then Messages.push(new notification("Cheat Activated","Summer Mode On","There can be only one!",4,ext.gfx.png.load("../img/notes_pu_gm.png")))

''Call level_up to initialize correct values for our player variable
level_up( player, ball(), 1 )

''Set our initial value for the timer variables
this_timer = timer
fps_timer = this_timer+1

var pu_bonus = 0ull
gravitron_active = -2

''Main Program loop
do
    if sm = 1 then
        if player.lives < 2 then player.lives = 2
    end if

    loop_time = timer-this_timer
    this_timer = timer
    fps+=1

    if this_timer>fps_timer then

        fps_timer = this_timer+1
        fps_string = "FPS " & fps
        fps=0

    end if

    if player.lives = 0 then exit do

    omx = mx
    omy = my

    getmouse( mx, my, , mbutt)

    if sm = 1 andalso multikey(fb.sc_w) andalso multikey(fb.sc_alt) then 'debug more time
        if this_timer>last_key_time then
            last_key_time = this_timer+.2

            player.timer_level += 500

        end if
    end if


    if sm = 1 andalso multikey(fb.SC_J) and multikey(fb.SC_ALT) then 'Debug jump to next level

        if this_timer>last_key_time then

            last_key_time = this_timer+.2

            player.score = 0

            level_up(player,ball(),1)

        end if

    end if

    if sm = 1 then
        var tin = inkey
        if tin = "0" then tin = "10"
        if tin = "-" then
            addPUBustron(PU_ENERGY)
        else
        select case cast(powerups,valint("-" & tin))
        case PU_GRAVITY
        addPUBustron(PU_GRAVITY)
        case PU_LOSPD
        addPUBustron(PU_LOSPD)
        case PU_HISPD
        addPUBustron(PU_HISPD)
        case PU_HISPD_GROW
        addPUBustron(PU_HISPD_GROW)
        case PU_LOSPD_GROW
        addPUBustron(PU_LOSPD_GROW)
        case PU_SHIELD
        addPUBustron(PU_SHIELD)
        case PU_SIDES
        addPUBustron(PU_SIDES)
        case PU_MOTIME
        addPUBustron(PU_MOTIME)
        case PU_NOTIME
        addPUBustron(PU_NOTIME)
        case PU_GRAVITRON
        addPUBustron(PU_GRAVITRON)

        end select
        end if
    end if


    if multikey(fb.SC_UP) then
        if music_volume < 255 then music_volume += 1
    end if
    if multikey(fb.sc_DOWN) then
        if music_volume > 0 then music_volume -= 1
    end if

    if multikey(fb.sc_right) then
        if sfx_volume < 255 then sfx_volume += 1
    end if
    if multikey(fb.sc_left) then
        if sfx_volume > 0 then sfx_volume -= 1
    end if

    if multikey(fb.SC_ESCAPE) orelse inkey=chr(255)+"k" then exit do

    if multikey(fb.SC_S) then 'Toggle FPS display

        if this_timer>last_key_time then

            last_key_time = this_timer+.2

            if showFPS = 0 then
                showFPS = 1
            else
                showFPS = 0
            end if

        end if

    end if

    if multikey(fb.SC_N) then 'skip music track
        if this_timer > last_key_time then
            last_key_time = this_timer+.2

            playNextSong()
        end if
    end if

    if multikey(fb.SC_P) then 'Toggle Pause

        if this_timer>last_key_time then

            last_key_time = this_timer+.2

            if isPaused = 0 then
                pre_paused_mx = mx
                pre_paused_my = my
                isPaused = 1
                song_pos = FSOUND_Stream_GetTime(song)
                FSOUND_Stream_Stop(song)
                if curMessage <> 0 then
                    notifcation_paused = curMessage->start - timer
                end if
                remove_pu_bold = remove_pu_b - timer
            else
                if pre_paused_mx > 0 then
                    setmouse pre_paused_mx, pre_paused_my
                end if
                isPaused = 0
                song_channel = FSOUND_Stream_Play(song_channel,song)
                FSOUND_Stream_SetTime(song,song_pos)
                song_pos = -1
                if curMessage <> 0 then
                    curMessage->start = timer + notifcation_paused
                end if
                remove_pu_b = timer + remove_pu_bold
            end if

        end if

    end if

    if isPaused = 1 andalso song_pos = -1 then
        song_pos = FSOUND_Stream_GetTime(song)
        FSOUND_Stream_Stop(song)
        if curMessage <> 0 then
            notifcation_paused = curMessage->start - timer
        end if
        remove_pu_bold = remove_pu_b - timer
    end if

    if multikey(fb.SC_F) then 'Toggle Wireframe mode

        if this_timer>last_key_time then

            last_key_time = this_timer+.2

            if drawFilled = 0 then
                drawFilled = 1
            else
                drawFilled = 0
            end if

        end if

    end if

    if mx < 0 then isPaused=1 'Pause the game if the mouse leaves the window

    if FSOUND_IsPlaying( song_channel ) = 0 andalso isPaused=0 then

        song_channel = playNextSong()

    end if

    FSOUND_SetSFXMasterVolume( sfx_volume )
    FSOUND_SetVolumeAbsolute( song_channel, music_volume )

    if isPaused = 0 then 'don't do the majority of game logic if paused

        if mx>-1 then

            if (mbutt and 1) then

                var mcheck = vec2f(mx,my)
                dim as integer bad_spot = 0

                for i as integer = 0 to player.max_balls - 1
                    if player.ball[i].active <> 0 then

                        dim as single dist = player.ball[i].p.Distance(mcheck)

                        if dist<player.ball[i].r then
                            bad_spot = 1
                        end if
                    end if
                next

                if bad_spot = 0 then

                    if ball_is_active = 0 then

                        ball_is_active = 1

                        for i as integer = 0 to player.max_balls - 1

                            if player.ball[i].active = 0 and player.ball[i].dead = 0 then

                                player.selected = i
                                player.ball[i].r = 5
                                player.ball[i].v = vec2f(0,0)
                                grow = 0
                                var spos = vec3f( player.ball[player.selected].p.x, player.ball[player.selected].p.y, 160 )
                                grow_channel = FSOUND_PlaySoundEx( grow_channel, SFX(SFX_GROW), 0, 1 )
                                FSOUND_3D_SetAttributes( grow_channel, @spos.x, 0 )
                                FSOUND_SetLoopMode( grow_channel, FSOUND_LOOP_NORMAL )
                                FSOUND_SetPaused(grow_channel, 0)
                                exit for

                            end if

                        next

                    end if

                end if
            end if

        end if

        if player.selected>-1 then

            var spos = vec3f( player.ball[player.selected].p.x, player.ball[player.selected].p.y, 160 )
            FSOUND_3D_SetAttributes( grow_channel, @spos.x, 0 )
            player.ball[player.selected].p.x = mx
            player.ball[player.selected].p.y = my
            player.ball[player.selected].r += ((player.ball[player.selected].r*.1)*(growth_rate*loop_time))
            player.ball[player.selected].m=player.ball[player.selected].r/1000
            player.ball[player.selected].col = rgba(255,255,0,128)

            grow+= player.ball[player.selected].r/10

            if grow >player.ball[player.selected].r then grow = 0


            if player.ball[player.selected].p.y>479-player.ball[player.selected].r then

                player.ball[player.selected].p.y=479-player.ball[player.selected].r
                player.ball[player.selected].v.y*=-.5
                player.ball[player.selected].v.x*=.35

                if abs(player.ball[player.selected].v.y)<.25 then
                    player.ball[player.selected].v.y = 0
                end if

                if player.ball[player.selected].v.y <> 0 then

                    var spos = vec3f( player.ball[player.selected].p.x, player.ball[player.selected].p.y, 0 )
                    player.ball[player.selected].sound_channel = FSOUND_PlaySoundEx( FSOUND_FREE, SFX(1), 0, 0 )
                    FSOUND_3D_SetAttributes( player.ball[player.selected].sound_channel, @spos.x, 0 )

                end if

                if sides_active = 0 then

                    player.ball[player.selected].active = 1
                    player.ball[player.selected].col = rgba(255,255,255,64)
                    player.ball[player.selected].glow = 1
                    player.selected = -1

                    goto jumpout

                end if

            end if

            if player.ball[player.selected].p.y-player.ball[player.selected].r<0 then

                player.ball[player.selected].p.y=player.ball[player.selected].r
                player.ball[player.selected].v.y*=-.5

                if abs(player.ball[player.selected].v.y)<.25 then
                    player.ball[player.selected].v.y = 0
                end if

                var spos = vec3f( player.ball[player.selected].p.x, player.ball[player.selected].p.y, 0 )
                player.ball[player.selected].sound_channel = FSOUND_PlaySoundEx( FSOUND_FREE, SFX(1), 0, 0 )
                FSOUND_3D_SetAttributes( player.ball[player.selected].sound_channel, @spos.x, 0 )

                if sides_active = 0 then

                    player.ball[player.selected].active = 1
                    player.ball[player.selected].col = rgba(255,255,255,64)
                    player.ball[player.selected].glow = 1
                    player.selected = -1

                    goto jumpout

                end if

            end if

            if player.ball[player.selected].p.x>639-player.ball[player.selected].r then

                player.ball[player.selected].p.x=639-player.ball[player.selected].r
                player.ball[player.selected].v.x*=-.5

                if abs(player.ball[player.selected].v.x)<.25 then
                    player.ball[player.selected].v.x = 0
                end if

                var spos = vec3f( player.ball[player.selected].p.x, player.ball[player.selected].p.y, 0 )
                player.ball[player.selected].sound_channel = FSOUND_PlaySoundEx( FSOUND_FREE, SFX(1), 0, 0 )
                FSOUND_3D_SetAttributes( player.ball[player.selected].sound_channel, @spos.x, 0 )

                if sides_active = 0 then

                    player.ball[player.selected].active = 1
                    player.ball[player.selected].col = rgba(255,255,255,64)
                    player.ball[player.selected].glow = 1
                    player.selected = -1

                    goto jumpout

                end if

            end if

            if player.ball[player.selected].p.x-player.ball[player.selected].r<0 then

                player.ball[player.selected].p.x=player.ball[player.selected].r
                player.ball[player.selected].v.x*=-.5

                if abs(player.ball[player.selected].v.x)<.25 then
                    player.ball[player.selected].v.x = 0
                end if

                var spos = vec3f( player.ball[player.selected].p.x, player.ball[player.selected].p.y, 0 )
                player.ball[player.selected].sound_channel = FSOUND_PlaySoundEx( FSOUND_FREE, SFX(1), 0, 0 )
                FSOUND_3D_SetAttributes( player.ball[player.selected].sound_channel, @spos.x, 0 )


                if sides_active = 0 then

                    player.ball[player.selected].active = 1
                    player.ball[player.selected].col = rgba(255,255,255,64)
                    player.ball[player.selected].glow = 1
                    player.selected = -1

                    goto jumpout

                end if

            end if



            var posit = vec2f(player.ball[player.selected].p)
            dim as single radius = player.ball[player.selected].r

            for i as integer = 1 to 20

                dim as single rangle = rnd*pi2
                rpoint(i,1).a = rangle
                rpoint(i,1).p = posit '+ vec2f(radius/5*sin(rangle), radius/5*cos(rangle) )

                for r as integer = 2 to 10

                    dim as single nr = radius/7
                    rangle = rpoint(i,r-1).a -1+rnd*2
                    rpoint(i,r).a = rangle
                    rpoint(i,r).p = rpoint(i,r-1).p + vec2f(nr*sin(rangle), nr*cos(rangle) )

                    dim as single bcheck = ((rpoint(i,r).p.y - posit.y)^2) + ((rpoint(i,r).p.x - posit.x)^2)

                    if bcheck>(radius-1)^2 or r = 10 then

                        dim as single dist = rpoint(i,r).p.Distance(posit)
                        rpoint(i,r).p = posit + ( rpoint(i,r).p - posit ) / dist * (radius-1)

                    end if

                next

            next



            for i as integer = 0 to player.max_balls - 1

                if i<>player.selected then

                    if player.ball[i].active <> 0 then

                        if in_aabb(player.ball[i].p, player.ball[player.selected].p, (player.ball[i].r+player.ball[player.selected].r) ) then

                            dist = player.ball[i].p.Distance( player.ball[player.selected].p )

                            if dist < (player.ball[i].r+player.ball[player.selected].r) then

                                player.ball[player.selected].active = 1
                                player.ball[player.selected].col = rgba(255,255,255,64)
                                player.ball[player.selected].glow = 1
                                player.selected = -1

                                goto jumpout

                            end if

                        end if

                    end if

                end if

            next



            for j as integer = 0 to ubound(ball)

                if in_aabb( player.ball[player.selected].p, ball(j).p, player.ball[player.selected].r + ball(j).r ) then

                    dist = player.ball[player.selected].p.Distance( ball(j).p )

                    if dist < (player.ball[player.selected].r + ball(j).r) then

                        if ball(j).bad > -1 then

                            var spos = vec3f( player.ball[player.selected].p.x, player.ball[player.selected].p.y, 160 )
                            if shield_active = 0 then player.ball[player.selected].dead = 1
                            if shield_active = 0 then player.popped = player.selected
                            if shield_active = 0 then pop_channel = FSOUND_PlaySoundEx( pop_channel, SFX(SFX_POP), 0, 0 )
                            if shield_active = 0 then FSOUND_3D_SetAttributes( pop_channel, @spos.x, 0 )
                            if shield_active = 0 then FSOUND_SetPaused(grow_channel, 1)
                            if shield_active = 0 then pop_count = 1
                            if shield_active = 0 andalso curMessage <> 0 then 'end current powerup early
                                curMessage->start = timer - 1
                            end if

                            dim as single randang
                            if shield_active = 0 then
                                for p as integer = 0 to ubound(particle)

                                    randang = rnd*pi2
                                    particle(p).p = player.ball[player.selected].p +vec2f( player.ball[player.selected].r*sin(randang), player.ball[player.selected].r*cos(randang))
                                    particle(p).v = vec2f(RndRange(-20.0,20.0), RndRange(-20.0,20.0))
                                    particle(p).v.Normalize
                                    particle(p).v*=RndRange(0.0,5.0)

                                next
                            end if
                            if shield_active = 0 then player.selected = -1

                            goto jumpout

                        else
                            activatepowerups:
                            select case ball(j).bad
                                case PU_ENERGY
                                    if player.lives < player.level + 1 then player.lives += 1
                                    Messages.push(new notification("Powerup Get","Additional Energy","Use the Schwartz!",3,ext.gfx.png.load("../img/notes_pu_energy.png")))
                                case PU_MOTIME
                                    player.timer_level += 1000
                                    Messages.push(new notification("Powerup Get","More Time","Use it wisely",3,ext.gfx.png.load("../img/notes_pu_motime.png")))

                                case PU_NOTIME
                                    if player.timer_level < 1000 then
                                        player.timer_level -= 100
                                    else
                                        player.timer_level -= 250
                                    end if
                                    pu_bonus += 500
                                    Messages.push(new notification("Powerup Get","Less Time","Better Hurry Up",3,ext.gfx.png.load("../img/notes_pu_notime.png")))

                                case PU_HISPD
                                    curBallspeed = 225f
                                    pu_bonus += 500
                                    Messages.push(new notification("Powerup Active","Faster","Bustrons",5,ext.gfx.png.load("../img/notes_pu_hispd.png"),new not_callback(@end_hispeed_bustrons,0)))

                                    for n as integer = 0 to ubound(ball)
                                        ball(n).v.Normalize
                                        ball(n).s = curBallspeed
                                        ball(n).v*= ball(n).s
                                    next

                                case PU_LOSPD
                                    curBallspeed = 75f
                                    Messages.push(new notification("Powerup Active","Slooooooow","Bustrons",10,ext.gfx.png.load("../img/notes_pu_lospd.png"),new not_callback(@end_lospeed_bustrons,0)))

                                    for n as integer = 0 to ubound(ball)
                                        ball(n).v.Normalize
                                        ball(n).s = curBallspeed
                                        ball(n).v*= ball(n).s
                                    next

                                case PU_GRAVITY
                                    fgrav = -fgrav
                                    Messages.push(new notification("Powerup Activated","Gravity Toggle","Goooo Science!",2,ext.gfx.png.load("../img/notes_pu_gravity.png")))
                                    'need to give some of the balls a slight nudge, so we'll just do them all instead of checking which need it
                                    for i as integer = 0 to player.max_balls-1
                                        player.ball[i].v.y+=((18.0*loop_time)*fgrav)
                                    next

                                case PU_HISPD_GROW
                                    old_growth = growth_rate
                                    Messages.push(new notification("Powerup Active","Stabilizer","Growth Acceleration",8,ext.gfx.png.load("../img/notes_pu_higrow.png"),new not_callback(@end_higrowth,@old_growth)))
                                    growth_rate*=2.5

                                case PU_LOSPD_GROW
                                    pu_bonus += 750
                                    old_growth = growth_rate
                                    Messages.push(new notification("Powerup Active","Stabilizer","Growth Stunted",4,ext.gfx.png.load("../img/notes_pu_logrow.png"),new not_callback(@end_logrowth,@old_growth)))
                                    growth_rate*=.5

                                case PU_SHIELD
                                    old_growth = growth_rate
                                    shield_active = 1
                                    Messages.push(new notification("Powerup Activated","Multi-Phase Shield","Activated!",8,ext.gfx.png.load("../img/notes_pu_shield.png"), new not_callback(@end_shield,@old_growth)))
                                    growth_rate *= 1.75

                                case PU_SIDES
                                    sides_active = 1
                                    Messages.push(new notification("Powerup Activated","Boundary Breach","Activated!",15,ext.gfx.png.load("../img/notes_pu_sides.png"), new not_callback(@end_sides,0)))

                                case PU_GRAVITRON
                                    gravitron_active = player.selected
                                    gravitron_size = 5
                                    old_growth = growth_rate
                                    growth_rate *= .75
                                    Messages.push(new notification("Powerup Activated","Gravitron","Activated!",15,ext.gfx.png.load("../img/notes_pu_blackhole.png"), new not_callback(@end_gravitron,@old_growth)))

                            end select
                            remove_pu = 1

                        end if

                    end if

                end if

            next

            if (mbutt and 1) = 0 then

                var tvel = vec2f(mx-omx, my-omy)
                var mag = tvel.Magnitude

                if mag=0.0 then mag = 1.0

                if mag>6.0 then mag = 6.0

                tvel.Normalize
                player.ball[player.selected].v = tvel*mag
                player.ball[player.selected].active = 1
                player.ball[player.selected].col = rgba(255,255,255,64)
                player.ball[player.selected].glow = 1
                player.selected = -1
                ball_is_active = 0

            end if

        end if

        jumpout:

        if (mbutt and 1) = 0 then ball_is_active = 0

        if ball_is_active = 0 then

            if grow_channel then

                FSOUND_SetPaused(grow_channel, 1)
                FSOUND_SetLoopMode( grow_channel, FSOUND_LOOP_OFF )

            end if

        end if

        for i as integer = 0 to player.max_balls - 1

            if player.ball[i].active <> 0 then

                player.ball[i].p+=(player.ball[i].v*bspeed)*loop_time
                player.ball[i].v+=vec2f(0,fgrav*loop_time)


                check_ball_2screen( player.ball[i], loop_time )

                for j as integer = 0 to player.max_balls - 1

                    if j<>i then

                        if player.ball[j].active <> 0 then

                            for resolve as integer = 0 to 20

                                if in_aabb(player.ball[i].p, player.ball[j].p, (player.ball[i].r+player.ball[j].r) ) then

                                    dist = player.ball[i].p.Distance( player.ball[j].p )

                                    if dist < (player.ball[i].r+player.ball[j].r) then

                                        dim as vec2f temp1 = (player.ball[i].p - player.ball[j].p)/dist
                                        player.ball[i].p += temp1
                                        player.ball[j].p -= temp1

                                        dim as vec2f pVec = player.ball[j].v - player.ball[i].v
                                        dim as vec2f fVec = player.ball[j].p - player.ball[i].p
                                        fVec.Normalize

                                        fVec *= pVec.Dot(fVec) * player.ball[i].m * player.ball[j].m

                                        player.ball[i].v +=  fVec / player.ball[i].m
                                        player.ball[j].v -=  fVec / player.ball[j].m

                                        check_ball_2screen( player.ball[i], loop_time )
                                        check_ball_2screen( player.ball[j], loop_time )

                                    end if

                                else

                                    exit for

                                end if

                            next

                        end if

                    end if

                next

            end if

        next


        dim as integer max_add_sounds, add_sound

        for i as integer = 0 to ubound(ball)

            for b as integer = 0 to 20

                ball(i).streamer(b).c-=12

            next

            ball(i).scount+=1

            if ball(i).scount>20 then ball(i).scount=0

            ball(i).streamer(ball(i).scount).p = ball(i).p
            ball(i).streamer(ball(i).scount).c = 255
            ball(i).op = ball(i).p

            if gravitron_active = -2 then
                ball(i).p += (ball(i).v*loop_time)
            else

                var dist = ball(i).p.distance(player.ball[gravitron_active].p)

                ball(i).v+= (player.ball[gravitron_active].p-ball(i).p)/(dist*.25)

                ball(i).p += (ball(i).v*loop_time)

            end if

            if ball(i).p.x>640 - ball(i).r then

                ball(i).p.x = 640 - ball(i).r
                ball(i).v.x*=-1.0
                add_sound = 1
            end if

            if ball(i).p.x - ball(i).r < 0 then

                ball(i).p.x = ball(i).r
                ball(i).v.x*=-1.0
                add_sound = 1

            end if

            if ball(i).p.y>480 - ball(i).r then

                ball(i).p.y = 480 - ball(i).r
                ball(i).v.y*=-1.0
                add_sound = 1

            end if

            if ball(i).p.y - ball(i).r < 25 then

                ball(i).p.y = 25 + ball(i).r
                ball(i).v.y*=-1.0
                add_sound = 1

            end if

            for j as integer = 0 to player.max_balls - 1

                if player.ball[j].active <> 0 or shield_active<> 0 then

                    if in_aabb( player.ball[j].p, ball(i).p, player.ball[j].r+ball(i).r ) then

                        dist = ball(i).p.Distance( player.ball[j].p )

                        if dist < (ball(i).r + player.ball[j].r) then

                            dim as vec2f temp1 = (ball(i).p - player.ball[j].p)/dist
                            ball(i).p = player.ball[j].p+(temp1*(player.ball[j].r+ball(i).r))
                            temp1.Normalize
                            ball(i).v = temp1*ball(i).s
                            add_sound = 2

                        end if

                    end if

                end if

            next

            for j as integer = 0 to ubound(ball)

                if in_aabb( ball(i).p, ball(j).p, ball(i).r+ball(j).r ) then

                    if i<>j then

                        dist = ball(i).p.Distance( ball(j).p )

                        if dist < (ball(i).r + ball(j).r) then

                            dim as vec2f temp1 = ( ball(i).p - ball(j).p ) / dist
                            ball(i).p += temp1
                            ball(j).p -= temp1
                            temp1.Normalize
                            ball(i).v = temp1*ball(i).s
                            ball(j).v = (temp1*ball(i).s)*-1.0
                            add_sound=2

                        end if

                    end if

                end if

            next

            'just some filtering to keep the bouncing sounds from getting out of control.
            if add_sound>0 then

                if max_add_sounds<2 then

                    max_add_sounds+=1

                    if ball(i).sound_time < this_timer then

                        ball(i).sound_time = this_timer+.1
                        var magvec = vec2f(ball(i).p - ball(i).op)

                        if abs(magvec.Magnitude)>=1.0 then

                            var spos = vec3f( ball(i).p.x, ball(i).p.y, 0 )
                            ball(i).sound_channel = FSOUND_PlaySoundEx( FSOUND_FREE, SFX(add_sound), 0, 0 )
                            FSOUND_3D_SetAttributes( ball(i).sound_channel, @spos.x, 0 )

                        end if

                    end if

                end if

            end if

        next

    end if 'isPaused

    var cam_targ = vec3f(320, 240, 0)

    FSOUND_3D_Listener_SetAttributes( @cam_targ.X, 0, 0,0,1, 0,1,0 )

    Big_Hairy_Ball_Count = 0
    filled_area = 0

    Var temp_fill = 0.0f

    ''Drawing loop
    screenlock

    if drawFilled = 1 then ''boom

        dim as integer r,g,b
        dim as integer sx,ex,sy,ey
        a = timer

        for y as integer = 0 to (240\4)-1

            sy = y*8
            ey = sy+7

            for x as integer = 0 to (320\4)-1

                sx = x*8
                ex = sx+7

                'ooooo trippy
                R = abs(64 + 96 * cos(a+x/(32+16*sin(y/70+a))))
                G = abs(64 + 96 * sin(a+y/(32-12*cos(x/100+a))))
                B = abs(64 + 96 * cos(a+(((R*sin(a))/128)^2 + ((G*cos(a))/128)^2)))

                for y2 as integer = sy to ey

                    for x2 as integer = sx to ex

                        scr[x2+y2*640] = rgb(R, G, B)

                    next

                next

            next

        next

    else


        put(0,0),wfbg_image, pset

    end if


    for i as integer = 0 to player.max_balls - 1

        if player.ball[i].glow > 0 then

                circle(player.ball[i].p.x, player.ball[i].p.y), player.ball[i].r+(player.ball[i].glow/24), rgba(255,255,0,255-player.ball[i].glow),,,,f

            player.ball[i].glow+=10

            if player.ball[i].glow>255 then player.ball[i].glow = 0

        end if

    next

    for i as integer = 0 to player.max_balls - 1

        if player.ball[i].active <> 0 or i = player.selected then

            if i = player.selected then

                for i as integer = 1 to 20

                    for r as integer = 2 to 10

                        line(rpoint(i,r-1).p.x, rpoint(i,r-1).p.y)-(rpoint(i,r).p.x, rpoint(i,r).p.y), RGBA(255, 255, 255, 255-(r*24))

                    next

                next


                if shield_active then

                    for l as integer = 5 to 360 step 5

                        dim as single r = player.ball[i].r- (player.ball[i].r/10)+(rnd*(player.ball[i].r/5))

                        line(player.ball[i].p.x+r*sin((l-5)*pi_180), player.ball[i].p.y+r*cos((l-5)*pi_180)) - (player.ball[i].p.x+r*sin(l*pi_180), player.ball[i].p.y+r*cos(l*pi_180)),rgba(255,255,255,128)

                    next

                end if


            end if

            if player.ball[i].active <> 0 then

                filled_area+= pi*player.ball[i].r^2

            else

                temp_fill = pi*player.ball[i].r^2

            end if
            '''draw stabilizer

                if player.selected = i then

                    if shield_active = 0 then
                        circle( player.ball[i].p.x, player.ball[i].p.y), player.ball[i].r, player.ball[i].col,,,,f
                        circle( player.ball[i].p.x, player.ball[i].p.y), player.ball[i].r, rgba(0,0,0,255)
                    else
                        circle( player.ball[i].p.x, player.ball[i].p.y), player.ball[i].r, rgba(0,0,128,128),,,,f
                    end if

                else
                    circle( player.ball[i].p.x, player.ball[i].p.y), player.ball[i].r, player.ball[i].col,,,,f
                    circle( player.ball[i].p.x, player.ball[i].p.y), player.ball[i].r, rgba(0,0,0,255)
                end if

                if gravitron_active = i then

                    gravitron_size-=loop_time*20
                    if gravitron_size<0 then
                        gravitron_size = 5
                    end if

                    for s as integer = 20 to 0 step -1

                        circle( player.ball[i].p.x, player.ball[i].p.y), player.ball[i].r-(gravitron_size+s), rgba(0,0,0,16),,,,f

                    next

                end if

        else






            if player.ball[i].dead then

                player.lives -= 1
                player.ball[i].dead = 0

            else

                Big_Hairy_Ball_Count+=1

            end if

        end if

    next

    if pop_count>0 then

        for p as integer = 0 to ubound(particle)

            particle(p).p+=(particle(p).v*particle_speed)*loop_time
            particle(p).v.y+= (fgrav*loop_time)
            particle(p).v.x+= (-particle(p).v.x*.1)*loop_time

                'circle(particle(p).p.x, particle(p).p.y),5-pop_count/25,rgba(RndRange(10,255),RndRange(10,255),RndRange(10,255),255-(pop_count*2)),,,,f
                circle(particle(p).p.x, particle(p).p.y),5-pop_count/25,rgba(255,(pop_count*2),(pop_count*2),255-(pop_count*2)),,,,f


        next

        pop_count+= (100.0*loop_time)

        if pop_count>400 then pop_count = 0

    end if

    for i as integer = 0 to ubound(ball)

        for s as integer = 0 to 20

                circle( ball(i).streamer(s).p.x-2+rnd*5, ball(i).streamer(s).p.y-2+rnd*5), ball(i).r-((255-ball(i).streamer(s).c)/32), mixalpha(ball(i).col,4),,,,f



        next


            circle( ball(i).p.x, ball(i).p.y), ball(i).r, ball(i).col,,,,f
            circle( ball(i).p.x, ball(i).p.y), ball(i).r, rgba(0,0,0,255)


        drawpowerups:
        select case ball(i).bad
            case PU_ENERGY
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_energy,trans
            case PU_GRAVITY
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_gravity,trans
            case PU_HISPD
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_hispd,trans
            case PU_LOSPD
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_lospd,trans
            case PU_HISPD_GROW
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_hispd_grow,trans
            case PU_LOSPD_GROW
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_lospd_grow,trans
            case PU_SHIELD
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_shield, trans
            case PU_SIDES
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_sides, trans
            case PU_MOTIME
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_timeup, trans
            case PU_NOTIME
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_timedown, trans
            case PU_GRAVITRON
                put(ball(i).p.x-8, ball(i).p.y-8),ipu_gravitron, trans
        end select

    next

    temp_score = pu_bonus + (player.level * int( (( Big_Hairy_Ball_Count + player.timer_level)*player.lives)*((filled_area)/SCR_AREA)/player.level))

    put (0,0), banner, pset
    draw string (320,3),str(player.level),,mfont,alpha
    draw string (420,4),str(temp_score),,mfont,alpha
    draw string (565,4),str(player.timer_level),,mfont,alpha

    'fill meter
    var ttemp_fill = ((((filled_area+temp_fill)*100)/SCR_AREA)/player.level_fill)*43
    for fill_meter as integer = 1 to ttemp_fill
        line (36+fill_meter,9)-(36+fill_meter,14), rgb(0,255,0)
    next

    'shields (lives)
    var shield_level = (player.lives/(player.level+1))*48
    for fill_meter as integer = 1 to shield_level
        line (125+fill_meter,9)-(125+fill_meter,16), rgb(0,255,0)
    next
    'ball count (power level)
    var power_level = (Big_Hairy_Ball_Count/player.max_balls)*44
    for fill_meter as integer = 1 to power_level
        line (211+fill_meter,9)-(211+fill_meter,15), rgb(0,255,0)
    next

    if showFPS = 1 then draw string (1,460), fps_string,,mfont,alpha

    if isPaused = 1 then
        line (160,120)-(480,360),rgb(128,128,128),BF
        line (160,120)-(480,360),rgb(255,255,255),B
        draw string (320-(ext.gfx.font.getTextWidth(mfont,"P A U S E D")/2),230), "P A U S E D",,mfont,alpha

    end if
    'todo: notifications
    if curMessage = 0 then
        curMessage = Messages.pop()
        if curMessage <> 0 then
            curMessage->start = curMessage->length + timer
        end if
    end if

    if curMessage <> 0 then
        if curMessage->start < timer then
            delete curMessage
            curMessage = 0
        end if
    end if

    if isPaused = 0 andalso curMessage <> 0 andalso curMessage->start > timer then

        put (320,420), note_img, alpha, 128
        if curMessage->icon <> 0 then put(322,430),curMessage->icon,alpha, 128
        draw string (360,425), curMessage->line1,, mfont, alpha
        draw string (360,445), curMessage->line2,, mfont, alpha
        draw string (360,460), curMessage->line3,, mfont, alpha
        draw string (336-ext.gfx.font.getTextWidth(mfont,str(int(curMessage->start - timer)+1))/2,465), str(int(curMessage->start - timer)+1),,mfont,alpha

    end if

    screensync 'vsync
    screenunlock 'end drawing loop

    sleep 1,1

    if isPaused = 0 andalso gravitron_active = -2 then player.timer_level -= 1

    if player.timer_level = 0 then

        setmouse 320, 1
        put (0,0), oot_img, pset

        if grow_channel then

            FSOUND_SetPaused(grow_channel, 1)
            FSOUND_SetLoopMode( grow_channel, FSOUND_LOOP_OFF )

        end if

        level_up( player, ball(), 0 )
        pu_bonus = 0


        'loop for input on button
        do
            var disposable_key = inkey
            getmouse mx, my,,mbutt

            if disposable_key = chr(27) then goto cleanup
            if disposable_key = chr(255)+"k" then goto cleanup

            if mbutt and 1 then
                if mx > 274 andalso mx < 381 andalso my > 253 andalso my < 355 then
                    exit do
                end if
            end if

            sleep 10,1

        loop
        cls
        sleep 99,1

        this_timer = timer

    end if


    if (filled_area*100)/SCR_AREA>=player.level_fill then

        player.score += temp_score
        cls
        windowtitle "Dr. Mudball's Laboratory!"
        setmouse 320, 1
        put (0,0), scorecard, pset
        draw string (450,145), int((Big_Hairy_Ball_Count/player.max_balls)*100) & "%",,mfont,alpha 'quark filler power level
        draw string (450,190), int((player.lives / (player.level+1)) *100) & "%",,mfont,alpha 'shields remaining
        draw string (450,240), int((((filled_area*100)/SCR_AREA) / player.level_fill) * 100) & "%",,mfont,alpha 'filled
        draw string (450,285), str(temp_score),,mfont,alpha 'level bonus
        draw string (450,325), str(player.score),,mfont,alpha 'score

        if grow_channel then

            FSOUND_SetPaused(grow_channel, 1)
            FSOUND_SetLoopMode( grow_channel, FSOUND_LOOP_OFF )

        end if

        level_up( player, ball(), 1 )
        pu_bonus = 0


        'loop for input on button
        do
            var disposable_key = inkey
            getmouse mx, my,,mbutt

            if disposable_key = chr(27) then goto cleanup
            if disposable_key = chr(255)+"k" then goto cleanup

            if mbutt and 1 then
                if mx > 409 andalso mx < 594 andalso my > 355 andalso my < 446 then
                    exit do
                end if
            end if

            sleep 10,1

        loop
        cls
        sleep 99,1

        windowtitle "Dr. Mudball's Laboratory!"
        this_timer = timer

    else

        if Big_Hairy_Ball_Count = 0 and ball_is_active = 0 then

            setmouse 320, 1
            put (0,0), ooqfp_img, pset


            if grow_channel then

                FSOUND_SetPaused(grow_channel, 1)
                FSOUND_SetLoopMode( grow_channel, FSOUND_LOOP_OFF )

            end if

            level_up( player, ball(), 0 )
            pu_bonus = 0


            'loop for input on button
            do
                var disposable_key = inkey
                getmouse mx, my,,mbutt

                if disposable_key = chr(27) then goto cleanup
                if disposable_key = chr(255)+"k" then goto cleanup

                if mbutt and 1 then
                    if mx > 274 andalso mx < 381 andalso my > 253 andalso my < 355 then
                        exit do
                    end if
                end if

                sleep 10,1

            loop
            cls
            sleep 99,1

            this_timer = timer

        end if

    end if

    FSound_Update()

    var rand_pu = RndRange(0,1000)

    if isPaused = 0 andalso cooldown < timer andalso  ubound(ball) <= player.level then
        select case rand_pu
            case 420, 320
                addPUBustron(PU_HISPD)
            case 983, 910, 718
                addPUBustron(PU_LOSPD)
            case 310, 14, 523, 120
                addPUBustron(PU_GRAVITY)
            case 666, 690
                addPUBustron(PU_HISPD_GROW)
            case 492, 162, 291
                addPUBustron(PU_LOSPD_GROW)
            case 792, 10
                addPUBustron(PU_SHIELD)
            case 998, 410
                addPUBustron(PU_SIDES)
            case 241, 563, 29
                addPUBustron(PU_MOTIME)
            case 681, 302
                addPUBustron(PU_NOTIME)
            case 555
                addPUBustron(PU_GRAVITRON)
            case 192, 13
                addPUBustron(PU_ENERGY)
        end select
    end if

    if remove_pu = 1 then
        redim preserve ball(player.level)
        remove_pu = 0
    end if

    if isPaused = 0 andalso remove_pu_b < timer then
        redim preserve ball(player.level)
        remove_pu = 0
    end if

    if gravitron_active = player.selected then pu_bonus += 1

loop 'end main loop

cleanup:
isPaused = 0
FSOUND_StopSound(grow_channel)
FSOUND_SetLoopMode( grow_channel, FSOUND_LOOP_OFF )

imagedestroy bg_image
delete[] player.ball
player.ball = null

player.score += temp_score

game_over(player)

chdir exepath

'save settings
var setxml = new ext.xml.tree
setxml->load(CONFIG_DIR & "settings.xml")
if setxml->root->child(0) <> null then
    setxml->root->child(0)->child("wireframe-mode")->attribute("value") = str(drawFilled)
    setxml->root->child(0)->child("music-volume")->attribute("value") = str(music_volume)
    setxml->root->child(0)->child("sfx-volume")->attribute("value") = str(sfx_volume)
    setxml->root->child(0)->child("show-fps")->attribute("value") = str(showFPS)
    setxml->unload(CONFIG_DIR & "settings.xml")

else

    LoadSettings(drawFilled,music_volume,sfx_volume,showFPS)
    setxml->load(CONFIG_DIR & "settings.xml")
    setxml->root->child(0)->child("wireframe-mode")->attribute("value") = str(drawFilled)
    setxml->root->child(0)->child("music-volume")->attribute("value") = str(music_volume)
    setxml->root->child(0)->child("sfx-volume")->attribute("value") = str(sfx_volume)
    setxml->root->child(0)->child("show-fps")->attribute("value") = str(showFPS)
    setxml->unload(CONFIG_DIR & "settings.xml")

end if
delete setxml

goto ithasbegun

#include once "powerup-callbacks.bas"

#include once "levels.bas"

#include once "util.bas"

#include once "cutscenes.bas"

